// datameta
// 根据数据定义字符串读取缓冲区中的数据项

package codec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"strconv"
	"strings"
)

const (
	//70功能码响应
	A70Res = ""
)

//按公式formula计算x返回结果
// 运算符|因数,...
// 运算符： +-*/
func Calc(x int, formula string) int {
	y := x
	for _, item := range strings.Split(formula, ",") {
		a, _ := strconv.Atoi(item[1:])
		switch item[:1] {
		case "+":
			y += a
		case "-":
			y -= a
		case "*":
			y *= a
		case "/":
			y /= a
		}
	}
	return y
}

//按defs的定义检测buf中的断线数据项
func CheckDx_feef(buf []byte, defs []string) (map[string]bool, error) {
	dx := make(map[string]bool)
	p := 0
	for i, d := range defs {
		var k, t, s string
		d = strings.TrimSpace(d)
		if i := strings.Index(d, ":"); i >= 0 {
			k, t, s = d[:i], d[i+1:i+2], d[i+2:]
		} else {
			t, s = d[:1], d[1:]
		}
		if s == "2" {
			h, l := buf[p+1], buf[p]
			if t[0] <= 'Z' {
				h, l = l, h
			}
			if h == 0xfe && l == 0xef {
				if k != "" {
					dx[k] = true
				} else {
					dx[strconv.Itoa(i)] = true
				}
			}
			p += 2
		} else if v, e := strconv.Atoi(s); e != nil {
			return dx, e
		} else {
			p += v
		}
	}
	return dx, nil
}

// 按defs的类型及长度定义解析数据
// def: 类型代码|字节数
// 类型代码： i-小端字节序有符号整数 I-大端字节序有符号整数
// u-小端字节序无符号整数 U-大端字节序无符号整数
// d-小端字节序BCD8421码整数 D-大端字节序BCD8421码整数
func ParseDatas(buf []byte, defs []string) ([]int, error) {
	dats := make([]int, 0, len(defs))
	br := bytes.NewReader(buf)
	var (
		uv16 uint16
		iv16 int16
		iv8  int8
	)
	for i, m := range defs {
		m = strings.TrimSpace(m)
		if i := strings.Index(m, ":"); i >= 0 {
			m = m[i+1:]
		}
		switch m {
		case "U", "U1", "u", "u1":
			if b, e := br.ReadByte(); e == nil {
				dats = append(dats, int(b))
			} else {
				return dats, e
			}
		case "U2":
			if e := binary.Read(br, binary.BigEndian, &uv16); e == nil {
				dats = append(dats, int(uv16))
			} else {
				return dats, e
			}
		case "u2":
			if e := binary.Read(br, binary.LittleEndian, &uv16); e == nil {
				dats = append(dats, int(uv16))
			} else {
				return dats, e
			}
		case "i1", "i", "I", "I1":
			if e := binary.Read(br, binary.BigEndian, &iv8); e == nil {
				dats = append(dats, int(iv8))
			} else {
				return dats, e
			}
		case "i2":
			if e := binary.Read(br, binary.LittleEndian, &iv16); e == nil {
				dats = append(dats, int(iv16))
			} else {
				return dats, e
			}
		case "I2":
			if e := binary.Read(br, binary.BigEndian, &iv16); e == nil {
				dats = append(dats, int(iv16))
			} else {
				return dats, e
			}
		case "D1", "d1", "D", "d":
			if b, e := br.ReadByte(); e == nil {
				v, e := Bcd8421Decode(b)
				if e != nil {
					fmt.Println("无效BCD数据", i, m, e)
				}
				dats = append(dats, v)
			} else {
				return dats, e
			}
		case "D2", "d2":
			buf := make([]byte, 2)
			if n, e := br.Read(buf); e == nil && n == len(buf) {
				if m[0] == 'd' {
					buf[0], buf[1] = buf[1], buf[0]
				}
				v, e := Bcd8421Decode2(buf[0], buf[1])
				if e != nil {
					fmt.Println("无效BCD数据", i, m, e)
				}
				dats = append(dats, v)
			} else if e == nil {
				return dats, io.EOF
			} else {
				return dats, e
			}
		default:
			if v, e := strconv.Atoi(m[1:]); e == nil {
				sli := make([]byte, v)
				br.Read(sli)
				dats = append(dats, 0)
			} else {
				return dats, e
			}
		}
	}
	return dats, nil
}
